<?php
declare (strict_types=1);

namespace app\command;

use Firebase\JWT\JWT;
use Swoole\Timer;
use Swoole\WebSocket\Server;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\Exception;
use think\facade\Log;

class WebSocketServer extends Command
{
    protected $websocket = null;

    protected function configure()
    {
        // 指令配置
        $this->setName('start_websocket_server')
            ->setDescription('the app\command\websocketserver command');
    }

    protected function execute(Input $input, Output $output)
    {
        // 指令输出
        $output->writeln('app\command\websocketserver');
        $this->init($input, $output);
    }

    protected function init(Input $input, Output $output)
    {
        //创建WebSocket Server对象，监听0.0.0.0:9502端口
        $this->websocket = new Server('0.0.0.0', 9502);
        $this->websocket->set([
            'worker_num' => 2,          //设置启动的worker进程数。【默认值：CPU 核数】
            'max_request' => 0,         //设置每个worker进程的最大任务数。【默认值：0 即不会退出进程】
            'daemonize' => false,       //守护进程化【默认值：0】
        ]);

        $this->websocket->on('Open', function ($ws, $request) {
            try {
                $authorization = $request->get['authorization'] ?? '';
                if ($authorization) {
                    try {
                        $authInfo = (array)JWT::decode($authorization, config('common.jwt.key'), config('common.jwt.allowed_algs'));
                        if (!$authInfo) throw new Exception('连接未授权！');
                        if ($authInfo['expire'] < time()) throw new Exception('授权已过期！');


                        /*
                         * 模拟发送数据
                        Timer::tick(3000, function () use ($ws, $request) {
                            if ($ws->exist($request->fd)) {
                                $ws->push($request->fd, json_encode(array(
                                    'action' => 'fresh',
                                    'serialNumber' => 'SL20221120001',
                                    'xAxisKey' => date('i:s'),
                                    'data' =>
                                        array(
                                            'serial_number' => 'SL20221120001',
                                            'frozen_thickness' => rand(1, 30),
                                            'hydrops_thickness' => rand(1, 30),
                                            'snows_thickness' => rand(1, 30),
                                            'temperature' => 11,
                                            'humidity' => rand(1, 30),
                                            'visibility' => rand(1, 30),
                                            'light_intensity' => rand(1, 30),
                                            'wind_speed' => rand(1, 30),
                                            'pm25' => rand(1, 30),
                                            'friction_coefficient' => rand(1, 30),
                                            'salinity' => rand(1, 30),
                                            'wind_direction' => rand(1, 30),
                                            'correct' => rand(1, 30),
                                        ),
                                ), 320));
                            }
                        });
                        */


                        //$ws->push($request->fd, 'welcome');
                    } catch (\UnexpectedValueException $e) {
                        echo '连接未授权' . PHP_EOL;
                        throw new Exception('授权后才能连接！');
                    }
                } else {
                    throw new Exception('连接未授权！');
                }
            } catch (\Exception $e) {
                $ws->push($request->fd, $e->getMessage());
                $ws->close($request->fd);
            }
        });

        $this->websocket->on('Message', function ($ws, $frame) {
            echo "Message:{$frame->data}\r\n";
            $data = json_decode($frame->data, true);
            $action = $data['action'] ?? '';
            if ('fresh' == $action) {
                foreach ($ws->connections as $fd) {
                    if ($ws->isEstablished($fd)) {
                        $ws->push($fd, $frame->data);
                        //Log::record("websocket推送数据{$fd}:" . var_export($frame->data, true), 'debug');
                    }
                }
            }
        });

        $this->websocket->on('Close', function ($ws, $fd) {
            echo "client-{$fd} is closed\n";
        });

        $this->websocket->start();
    }
}
